/*
 * Copyright 2003-2006 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.nanhill.commons.id;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;

import org.nanhill.commons.id.random.SessionIdGenerator;
import org.nanhill.commons.id.serial.AlphanumericGenerator;
import org.nanhill.commons.id.serial.LongGenerator;
import org.nanhill.commons.id.serial.NumericGenerator;
import org.nanhill.commons.id.serial.PrefixedAlphanumericGenerator;
import org.nanhill.commons.id.serial.PrefixedLeftPaddedNumericGenerator;
import org.nanhill.commons.id.serial.PrefixedNumericGenerator;
import org.nanhill.commons.id.uuid.UUID;
import org.nanhill.commons.id.uuid.VersionFourGenerator;
import org.nanhill.commons.id.uuid.VersionOneGenerator;

/**
 * A concrete identifier sequence factory. This is the default factory used by
 * commons-uid.
 * 
 * @author Commons-Id team
 * @version $Id: DefaultIdentifierGeneratorFactory.java,v 1.1 2006/09/20 06:55:58 alin Exp $
 */
public class DefaultIdentifierGeneratorFactory extends
		IdentifierGeneratorFactory implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 2577399381687692319L;

	/**
	 * Package scope constructor.
	 */
	public DefaultIdentifierGeneratorFactory() {
		super();
	}

	/**
	 * <p>
	 * Gets a new {@link LongIdentifierGenerator} that generates a sequence of
	 * Long objects increasing in value.
	 * </p>
	 * 
	 * <p>
	 * The sequence will wrap when the maximum <code>long</code> value is
	 * reached and return negative numbers. It will start from zero.
	 * </p>
	 * 
	 * @return a new LongIdentifier with wrapping behavior
	 */
	public LongIdentifierGenerator longGenerator() {
		return new LongGenerator(true, 0L);
	}

	/**
	 * <p>
	 * Gets a new {@link LongIdentifierGenerator} that generates a sequence of
	 * Long objects increasing in value.
	 * </p>
	 * 
	 * @param wrap
	 *            should the sequence wrap when it reaches the maximum long
	 *            value (or throw an {@link IllegalStateException})
	 * @param initialValue
	 *            the initial long value to start at
	 * @return a new LongIdentifier with the specified properties
	 */
	public LongIdentifierGenerator longGenerator(boolean wrap, long initialValue) {
		return new LongGenerator(wrap, initialValue);
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size in base-36.
	 * </p>
	 * 
	 * <p>
	 * The sequence will wrap when the maximum size (15) is reached.
	 * </p>
	 * 
	 * @return a new StringIdentifierGenerator
	 */
	public StringIdentifierGenerator alphanumericGenerator() {
		return new AlphanumericGenerator(
				true,
				AbstractStringIdentifierGenerator.DEFAULT_ALPHANUMERIC_IDENTIFIER_SIZE);
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size in base-36.
	 * </p>
	 * 
	 * @param wrap
	 *            should the factory wrap when it reaches the maximum size (or
	 *            throw an IllegalStateException)
	 * @param size
	 *            the number of characters the id should fill
	 * 
	 * @return a new StringIdentifierGenerator
	 */
	public StringIdentifierGenerator alphanumericGenerator(boolean wrap,
			int size) {
		return new AlphanumericGenerator(wrap, size);
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size in base-36,
	 * starting at an initial value.
	 * </p>
	 * 
	 * @param wrap
	 *            should the factory wrap when it reaches the maximum size (or
	 *            throw an IllegalStateException)
	 * @param initialValue
	 *            the initial value to start at
	 * 
	 * @return a new StringIdentifierGenerator
	 */
	public StringIdentifierGenerator alphanumericGenerator(boolean wrap,
			String initialValue) {
		return new AlphanumericGenerator(wrap, initialValue);
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size.
	 * </p>
	 * 
	 * <p>
	 * The sequence will wrap when the maximum <code>long</code> value is
	 * reached and return negative numbers. It will start from zero.
	 * </p>
	 * 
	 * @return a new StringIdentifierGenerator
	 */
	public StringIdentifierGenerator numericGenerator() {
		return new NumericGenerator(true, 0L);
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size.
	 * </p>
	 * 
	 * @param wrap
	 *            should the sequence wrap when it reaches the maximum long
	 *            value (or throw an IllegalStateException)
	 * @param initialValue
	 *            the initial long value to start at
	 * @return a new StringIdentifierGenerator
	 */
	public StringIdentifierGenerator numericGenerator(boolean wrap,
			long initialValue) {
		return new NumericGenerator(wrap, initialValue);
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects that appear to be random and are suitable for use as
	 * session identifiers.
	 * </p>
	 * 
	 * 
	 * @return a new StringIdentifierGenerator
	 */
	public StringIdentifierGenerator sessionIdGenerator() {
		return new SessionIdGenerator();
	}

	/**
	 * <p>
	 * Gets a new {@link IdentifierGenerator} that generates version one UUID
	 * Obejcts that conform to the <a
	 * href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-02.txt">
	 * IETF Draft UUID specification</a>.
	 * </p>
	 * 
	 * 
	 * @return a new IdentifierGenerator that generates version one UUIDs.
	 * @throws NoSuchMethodException
	 *             exception thrown while instantiating the generator.
	 * @throws InvocationTargetException
	 *             exception thrown while instantiating the generator.
	 * @throws IllegalAccessException
	 *             exception thrown while instantiating the generator.
	 * @throws InstantiationException
	 *             exception thrown while instantiating the generator.
	 */
	public IdentifierGenerator<UUID> uuidVersionOneGenerator()
			throws NoSuchMethodException, InvocationTargetException,
			IllegalAccessException, InstantiationException {
		return VersionOneGenerator.getInstance();
	}

	/**
	 * <p>
	 * Gets a new {@link IdentifierGenerator} that generates version four UUID
	 * Obejcts that conform to the <a
	 * href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-02.txt">
	 * IETF Draft UUID specification</a>.
	 * </p>
	 * 
	 * 
	 * @return a new IdentifierGenerator that generates version four UUIDs.
	 */
	public IdentifierGenerator<UUID> uuidVersionFourGenerator() {
		return new VersionFourGenerator();
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates an
	 * incrementing number in base 36 with a prefix as a String object.
	 * </p>
	 * 
	 * @param prefix
	 *            prefix, must not be null
	 * @param wrap
	 *            should the factory wrap when it reaches the maximum value that
	 *            can be represented in <code>size</code> base 36 digits (or
	 *            throw an exception)
	 * @param size
	 *            the size of the identifier, including prefix length
	 * @throws IllegalArgumentException
	 *             if prefix is null or size less prefix length is not at least
	 *             one
	 */
	public StringIdentifierGenerator prefixedAlphanumericGenerator(
			String prefix, boolean wrap, int size) {
		return new PrefixedAlphanumericGenerator(prefix, wrap, size);
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size, prefixed by an
	 * initial string and left-padded to make all strings the same length
	 * </p>
	 * 
	 * @param prefix
	 *            prefix, must not be null or empty
	 * @param wrap
	 *            should the factory wrap when it reaches the maximum value that
	 *            can be represented in <code>size</code> base 10 digits (or
	 *            throw an exception)
	 * @param size
	 *            the size of the identifier, including prefix length
	 * @throws IllegalArgumentException
	 *             if prefix is null or size less prefix length is less than 1
	 */
	public StringIdentifierGenerator prefixedLeftPaddedNumericGenerator(
			String prefix, boolean wrap, int size) {
		return new PrefixedLeftPaddedNumericGenerator(prefix, wrap, size);
	}

	/**
	 * <p>
	 * Gets a new {@link StringIdentifierGenerator} that generates a sequence of
	 * String objects representing numbers increasing in size, prefixed by an
	 * initial string.
	 * </p>
	 * 
	 * @param prefix
	 *            prefix, must not be null
	 * @param wrap
	 *            should the sequence wrap when it reaches the maximum long
	 *            value (or throw an IllegalStateException)
	 * @param initialValue
	 *            the initial long value to start at
	 * @return a new StringIdentifierGenerator
	 * @throws IllegalArgumentException
	 *             if prefix is null
	 */
	public StringIdentifierGenerator prefixedNumericGenerator(String prefix,
			boolean wrap, long initialValue) {
		return new PrefixedNumericGenerator(prefix, wrap, initialValue);
	}
}
